#include "kthread.h"
#include "param.h"
#include "types.h"
#include "user.h"
#include "fs.h"
#include "fcntl.h"
#include "syscall.h"
#include "traps.h"
#include "memlayout.h"
int mutex;
int cv_counter, bufferSize = 6, shouldExit = 0;
int CVempty, CVfull;

void *testMutex(){
  printf(1, "+ 1 I'm (%d, %d)\n", getpid(), kthread_id());
  kthread_mutex_lock(mutex);
  printf(1, "+ 2 I'm (%d, %d). And I hold mutex %d\n", getpid(), kthread_id(), mutex);

  if(kthread_id() == 1)
//     kthread_join(2);
    sleep(100);
  else
    sleep(100);
  
  printf(1, "+ 3 I'm (%d, %d). And I still hold mutex %d\n", getpid(), kthread_id(), mutex);
  kthread_mutex_unlock(mutex);
  printf(1, "+ 4 I'm (%d, %d). And I released mutex %d\n", getpid(), kthread_id(), mutex);
  
  
  printf(1, "+ 5 I'm (%d, %d), exiting...\n", getpid(), kthread_id());
  kthread_exit();
  return 0;
}

void *testCV_producer(){
  
  printf(1, "producer (%d, %d): starting while-loop\n", getpid(), kthread_id());
  while(1){
    kthread_mutex_lock(mutex);
    while(cv_counter < bufferSize){
      printf(1, "producer (%d, %d): adding 1 to %d\n", getpid(), kthread_id(), cv_counter);
      cv_counter++;
      kthread_cond_signal(CVempty);
    }
    printf(1, "producer (%d, %d): sleeping! buffer: %d\n", getpid(), kthread_id(), cv_counter);
    if(shouldExit)
      break;
    kthread_cond_signal(CVempty);
    kthread_cond_wait(CVfull, mutex);
    kthread_mutex_unlock(mutex);
  }
  printf(1, "producer exiting..\n");
  kthread_exit();
  return 0;
}

void *testCV_consumer(){
  int reached=0;
  int max = 10;

  sleep(100);
  printf(1, "consumer (%d, %d): starting while-loop\n", getpid(), kthread_id());
  while(reached < max){
    printf(1, "consumer (%d, %d): reached: %d - buffer: %d\n", getpid(), kthread_id(), cv_counter, reached);
    kthread_mutex_lock(mutex);
    if(cv_counter == 0){
      printf(1, "consumer (%d, %d): calling producer and sleeping\n", getpid(), kthread_id());
      kthread_cond_signal(CVfull);
      kthread_cond_wait(CVempty, mutex);
    }
    kthread_mutex_unlock(mutex);
    cv_counter--;
    reached++;
  }
  shouldExit = 1;
  kthread_cond_signal(CVfull);
  printf(1, "consumer (%d, %d): exiting, buffer: %d\n", getpid(), kthread_id(), cv_counter);
  kthread_exit();
  return 0;
}

/**/
// Test CV
int main(){

  mutex = kthread_mutex_alloc();
  CVfull = kthread_cond_alloc();
  CVempty = kthread_cond_alloc();
  printf(1, "Hi, i'm the main! Just allocated mutex: %d, CVfull: %d, CVempty: %d\n",mutex, CVfull, CVempty);
  void* stack = malloc(MAX_STACK_SIZE/2);
  kthread_create(testCV_consumer, stack, MAX_STACK_SIZE/2);
//   stack = malloc(MAX_STACK_SIZE/2);
//   kthread_create(testCV_consumer, stack, MAX_STACK_SIZE/2);
  stack = malloc(MAX_STACK_SIZE/2);
  kthread_create(testCV_producer, stack, MAX_STACK_SIZE/2);

  kthread_join(1);
  kthread_join(2);
//   kthread_join(3);
  kthread_cond_dealloc(CVfull);
  kthread_cond_dealloc(CVempty);
  kthread_mutex_dealloc(mutex);
  
  
  kthread_exit();
  return 0;
}
/**/

// Test mutex
/*
int main(){
  printf(1, "\n+ I'm (%d, %d). the main proccess\n", kthread_id());
  
  mutex = kthread_mutex_alloc();
    
   void* stack = malloc(MAX_STACK_SIZE);
   kthread_create(testMutex, stack, MAX_STACK_SIZE);
   stack = malloc(MAX_STACK_SIZE);
   kthread_create(testMutex, stack, MAX_STACK_SIZE);
   stack = malloc(MAX_STACK_SIZE);
   kthread_create(testMutex, stack, MAX_STACK_SIZE);
   stack = malloc(MAX_STACK_SIZE);
   kthread_create(testMutex, stack, MAX_STACK_SIZE);

  printf(1, "+ back in the main\n");
//   sleep(100);
  kthread_join(1);
  kthread_join(2);
  kthread_join(3);
  kthread_join(4);
  kthread_mutex_dealloc(mutex);
  printf(1, "+ I'm (%d, %d) - the main. And I deallocated mutex %d\n", getpid(), kthread_id(), mutex);
   kthread_exit();
//   exit();
  return 1;
}
*/
